package com.cmict.data.system.service.portal;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.http.HtmlUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cmict.data.form.api.task.CurrencyDataApi;
import com.cmict.data.framework.common.pojo.CommonResult;
import com.cmict.data.framework.common.pojo.PageResult;
import com.cmict.data.framework.security.core.util.SecurityFrameworkUtils;
import com.cmict.data.form.api.task.FormDataApi;
import com.cmict.data.form.api.task.dto.SysFormDTO;
import com.cmict.data.framework.tenant.core.aop.TenantIgnore;
import com.cmict.data.infra.api.rdb.RdbApi;
import com.cmict.data.infra.api.rdb.dto.SourceDTO;
import com.cmict.data.system.controller.admin.portal.vo.*;
import com.cmict.data.system.convert.portal.PortalConvert;
import com.cmict.data.system.dal.dataobject.permission.MenuDO;
import com.cmict.data.system.dal.dataobject.portal.PortalDO;
import com.cmict.data.system.dal.mysql.portal.PortalMapper;
import com.cmict.data.system.dal.mysql.user.AdminUserMapper;
import com.cmict.data.system.service.permission.MenuService;
import com.cmict.data.system.service.permission.PermissionService;
import com.cmict.data.system.service.user.AdminUserService;
import com.cmict.data.system.controller.admin.portal.vo.*;
import io.swagger.util.Json;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.cmict.data.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.cmict.data.system.enums.ErrorCodeConstants.*;


/**
 * 门户 Service 实现类
 *
 * @author awesome
 */
@Service
@Validated
@Slf4j
public class PortalServiceImpl implements PortalService {

    @Resource
    private PortalMapper portalMapper;
    @Resource
    private AdminUserMapper userMapper;
    @Resource
    private AdminUserService adminUserService;
    @Resource
    private MenuService menuService;

    @Resource
    private PermissionService permissionService;
    @Resource
    private FormDataApi formDataApi;

    @Resource
    private CurrencyDataApi currencyDataApi;

    @Autowired
    private RdbApi rdbApiService;


    @Value("${spring.datasource.dynamic.datasource.slave.name}")
    private String tableSchema;

    @Value("${spring.datasource.dynamic.datasource.master.name}")
    private String tableMaster;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createPortal(PortalCreateReqVO createReqVO) {
        if(portalMapper.selectCount("portal_name",createReqVO.getPortalName()) > 0){
            throw exception(PORTAL_NAME_EXIST_ERROR);
        }
        if(portalMapper.selectCount("portal_number",createReqVO.getPortalNumber()) > 0){
            throw exception(PORTAL_NUMBER_EXIST_ERROR);
        }
        if(createReqVO.getIsBase()!= null && createReqVO.getIsBase()){
            return Long.MIN_VALUE;
        }
        // 插入
        PortalDO portal = PortalConvert.INSTANCE.convert(createReqVO);
        portalMapper.insert(portal);
        if("move".equals(createReqVO.getSource())){
            Long tenantId = SecurityFrameworkUtils.getLoginUser().getTenantId();
            String sql = "INSERT INTO sys_move VALUES (0, '"+createReqVO.getAppid()+"', '"+createReqVO.getAscription()+"', "+portal.getId()+", "+tenantId+")";
            portalMapper.inMoveData(sql);
        }
        // 返回
        return portal.getId();
    }

    @Override
    public void updatePortal(PortalUpdateReqVO updateReqVO) {
        // 校验存在
        this.validatePortalExists(updateReqVO.getId());
        updateReqVO.setPortalName(HtmlUtil.filter(updateReqVO.getPortalName()));
        updateReqVO.setPortalNumber(HtmlUtil.filter(updateReqVO.getPortalNumber()));
        updateReqVO.setPortalDesc(HtmlUtil.filter(updateReqVO.getPortalDesc()));
        Long aLong = portalMapper.selectCount(new QueryWrapper<PortalDO>()
                .eq("portal_name", updateReqVO.getPortalName())
                .ne("id", updateReqVO.getId())
        );
        if(aLong > 0){
            throw exception(PORTAL_NAME_EXIST_ERROR);
        }
        Long bLong = portalMapper.selectCount(new QueryWrapper<PortalDO>()
                .eq("portal_number", updateReqVO.getPortalNumber())
                .ne("id", updateReqVO.getId())
        );
        if(bLong > 0){
            throw exception(PORTAL_NUMBER_EXIST_ERROR);
        }
        if(updateReqVO.getIsBase()!= null && updateReqVO.getIsBase()){
            return ;
        }
        // 更新
        PortalDO updateObj = PortalConvert.INSTANCE.convert(updateReqVO);
        portalMapper.updateById(updateObj);
    }

    @Override
    public void deletePortal(Long id) {
        // 校验存在
        this.validatePortalExists(id);
        // 删除
        PortalDO sysForm = portalMapper.selectById(id);
        if(ObjectUtil.isNotEmpty(sysForm.getManageMenuId())){
            if(ObjectUtil.isNotEmpty(menuService.selectById(sysForm.getManageMenuId()))){
                menuService.deleteMenu(sysForm.getManageMenuId());
            }
        }
        portalMapper.deleteById(id);

    }

    @Override
    public PortalDO getPortalManageMenuId(Long id) {
        // 校验存在
        this.validatePortalExists(id);
        // 获取
        return portalMapper.selectOneManageMenuId(id);
    }

    @Override
    public void deletePortalNoMenu(Long id) {
        // 校验存在
        this.validatePortalExists(id);
        // 删除
        //PortalDO sysForm = portalMapper.selectById(id);
        //menuService.deleteMenu(sysForm.getManageMenuId());
        portalMapper.deleteById(id);

    }

    private void validatePortalExists(Long id) {
        if (portalMapper.selectById(id) == null) {
            throw exception(PORTAL_NOT_EXIST_ERROR);
        }
    }

    @Override
    public PortalDO getPortal(Long id) {
        return portalMapper.selectById(id);
    }

    @Override
    public List<PortalDO> getPortalList(Collection<Long> ids) {
        return portalMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<PortalDO> getPortalPage(PortalPageReqVO pageReqVO) {
        return portalMapper.selectPage(pageReqVO);
    }

    @Override
    public List<PortalDO> getPortalList(PortalExportReqVO exportReqVO) {
        return portalMapper.selectList(exportReqVO);
    }

    @Override
    @TenantIgnore
    public Map<Object, Object> getMoveOne(String id, int isReference) {
        String sql ="";
        if(isReference!=0 && isReference!=1){
            sql = "select * from sys_move,sys_portal where sys_move.portal_id = sys_portal.id and sys_move.appid = '"+ id +"' and sys_portal.deleted = 0";
        }else{
            sql = "select * from sys_move,sys_portal where sys_move.portal_id = sys_portal.id and sys_move.appid = '"+ id +"' and  sys_portal.is_reference = "+ isReference +" and sys_portal.deleted = 0";
        }
        Map<Object, Object> vo = portalMapper.getMovePortal(sql);
        //Map<Object, Object> cloum = portalMapper.getMoveColumn(sql);
        return vo;
    }

    @Override
    public PageResult<PortalRespVO> getPortalPageRelease(PortalPageReqVO reqVO) {
        PageResult<PortalDO> pageResult = portalMapper.selectPageNoRelease(reqVO);
        if (CollUtil.isEmpty(pageResult.getList())) {
            return new PageResult<>(pageResult.getTotal()); // 返回空
        }
//        // 获得拼接需要的数据
//        Collection<Long> categoryIds = convertList(pageResult.getList(), PortalDO::getCategoryId);
//        Map<Long, SysCategory> categoryMap = sysCategoryService.getSysCategoryMap(categoryIds);
        List<MenuDO> menuList = menuService.getMenus();
        Map<Long, MenuDO> menuMap = menuList.stream().collect(Collectors.toMap(MenuDO::getId, Function.identity(), (v1, v2)->v1));
        // 拼接结果返回
        List<PortalRespVO> portalList = new ArrayList<>(pageResult.getList().size());
        pageResult.getList().forEach( portal -> {
            PortalRespVO portalRespVO = new PortalRespVO();
            BeanUtils.copyProperties(portal,portalRespVO);
            if("move".equals(portal.getSource())){
                String sql = "SELECT appid,ascription FROM sys_move where portal_id = " +portal.getId();
                Map<Object, Object> cloum = portalMapper.getMoveColumn(sql);
                if(ObjectUtil.isNotEmpty(cloum)){
                    portalRespVO.setAppid((String) cloum.get("appid"));
                    portalRespVO.setAscription((String) cloum.get("ascription"));
                }
            }
//            sysFormItemRespVO.setSysCategory(categoryMap.get(portal.getCategoryId()));
//            AdminUserDO user = adminUserService.getUser(Long.valueOf(portal.getCreator()));
//            if(user !=null ){
//                portalRespVO.setCreatorName(adminUserService.getUser(Long.valueOf(portal.getCreator())).getUsername());
                portalRespVO.setManageMenu(menuMap.get(portal.getManageMenuId()));
                portalList.add(portalRespVO);
//            }

        });
        return new PageResult<>(portalList, pageResult.getTotal());
    }


    @Override
    public List<SysFormDTO> getTableNameList() {
        List<SysFormDTO> sysFormDOS = formDataApi.selectListRelease();
        return sysFormDOS;
    }


    // 废弃---------------------  废弃
    @Override
    public List<Map<String,Object>> getFieldNameList(String tableName,String type) {

        String sql = "SELECT  column_name  as columnName,column_type  as columnType,column_comment  as comment, CONCAT(column_name , '_' ,column_comment) as columnComment FROM INFORMATION_SCHEMA.COLUMNS  WHERE   table_schema= '" + tableSchema + "' AND   table_name ='"+tableName+"';";

        return portalMapper.getTableNameList(sql);
    }

    @Override
    public BigDecimal getFunData(String fun, String fieldName, String tableName) {
        SourceDTO sourceDTO = rdbApiService.getSourceDOById(Long.valueOf(tableName)).getCheckedData();
        BigDecimal  funData = null;
        try {
        String sql = "SELECT IFNULL("+ fun +"( CAST(sp." + fieldName + " AS DOUBLE ) ),0) AS num FROM (" + sourceDTO.getSqlSentence() + ") sp INNER JOIN  " + tableMaster + ".system_users sm ON sp.`creator`= sm.id " ;
         log.info("sql:   "+sql);
            funData = portalMapper.getFunData(sql).setScale(2, BigDecimal.ROUND_HALF_UP);

        }catch (Exception e){
            e.printStackTrace();
            return null;
        }

        return funData;
    }
    @Override
    public Set<SysFormDTO> getUserFormList(Long userId){
        // 1、根据当前用户角色id获取当前用户的菜单id
        Set<Long> menuIds =  permissionService.getUserMenuIds(userId);
        // 2、根据菜单id获取当前用户的表单信息
        Set<Long> formMenuIds = formDataApi.getUserMenuId();
        formMenuIds.addAll(formDataApi.getManageMenuId());
        Set<Long> loginUserFormMenuIds = new HashSet<>(formMenuIds);
        loginUserFormMenuIds.retainAll(menuIds);
        String formMenuId ="'"+ StringUtils.join(loginUserFormMenuIds,"','")+"'";
        Set<SysFormDTO> sysForms = formDataApi.getSysFormByFormMenuIds(formMenuId);
        return sysForms;
    }

    @Override
    public void batchDeletePortal(Collection<Long> ids) {
        for (Long id : ids) {
            PortalDO sysForm = portalMapper.selectById(id);
            if(ObjectUtil.isNotEmpty(sysForm.getManageMenuId())){
                if(ObjectUtil.isNotEmpty(menuService.selectById(sysForm.getManageMenuId()))){
                    menuService.deleteMenu(sysForm.getManageMenuId());
                }
            }
        }
        portalMapper.deleteBatchIds(ids);
    }

    @Override
    public Object getFieldData(String fieldName, String tableName,String type) {
        SourceDTO sourceDTO = rdbApiService.getSourceDOById(Long.valueOf(tableName)).getCheckedData();
        if(StringUtils.isNoneBlank(type) && type.equals("dashboard")){
            //仪表盘
                String fun ="SUM";
                String sql = "SELECT IFNULL("+ fun +"( sp." + fieldName + "),0) AS num FROM (" + sourceDTO.getSqlSentence() + ") sp INNER JOIN  " + tableMaster + ".system_users sm ON sp.`creator`= sm.id " ;
                log.info("sql:   "+sql);

            BigDecimal  funData = null;
            try {
                funData = portalMapper.getFunData(sql).setScale(2, BigDecimal.ROUND_HALF_UP);
            }catch (Exception e){
                e.printStackTrace();
                return null;
            }

            return funData;

        }
        String sql = "SELECT sp." + fieldName +" FROM (" + sourceDTO.getSqlSentence() + ") sp INNER JOIN  " + tableMaster + ".system_users sm ON sp.`creator`= sm.id ";
        log.info("sql:   "+sql);

        List<String>  fieldData = portalMapper.getFieldData(sql);

        return fieldData;
    }


    @Override
    public Object getChartData(String fieldNameX, String fieldNameY, String tableName, String type) {
        SourceDTO sourceDTO = rdbApiService.getSourceDOById(Long.valueOf(tableName)).getCheckedData();

        TreeMap<String, Object> treeMap = new TreeMap<>();
        try{
            String sql = "SELECT  sp." + fieldNameX + "  FROM (" + sourceDTO.getSqlSentence() + ") sp INNER JOIN  " + tableMaster + ".system_users sm ON sp.`creator`= sm.id "  + " GROUP BY sp." + fieldNameX + " ORDER BY  CAST(sp." + fieldNameX + " AS DOUBLE )" ;
            List<String>  fieldData = portalMapper.getFieldData(sql);
            treeMap.put("X",fieldData);
            String sql2 = " SELECT COUNT( sp." + fieldNameY + ") FROM (" + sourceDTO.getSqlSentence() + ") sp INNER JOIN   " + tableMaster + ".system_users sm ON sp.`creator`= sm.id " +  " GROUP BY sp." + fieldNameX + " ORDER BY  CAST(sp." + fieldNameX + " AS DOUBLE )" ;
            List<String>  fieldData2 = portalMapper.getFieldData(sql2);
            treeMap.put("Y",fieldData2);
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }

        return treeMap;
    }

}
